package fnic.prehand.augment.resource;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import org.apache.log4j.Logger;

import fnic.prehand.augment.AppInfo;
import fnic.prehand.augment.District;
import fnic.prehand.augment.IpInfo;
import fnic.prehand.augment.Isp;
import fnic.prehand.augment.UserInfo;

/**
 * 扩维模块所需要的资源数据(IP\用户组等)，大部分复用以前预处理代码。SingleMode
 * @author Wu
 *
 */
public class AugmentResource {
	private static final Logger log = Logger.getLogger(AugmentResource.class);
	private static AugmentResource resource  = new AugmentResource();
	//资源数据
	private final List<IpInfo> ipDB = new ArrayList<IpInfo>();
	private final List<District> districtDB = new ArrayList<District>();
	private final List<Isp> ispDB = new ArrayList<Isp>();
	private final Map<Long,UserInfo> userInfoDB = new HashMap<Long,UserInfo>();
	private final Map<Long,AppInfo> appInfoDB = new HashMap<Long,AppInfo>();

	private  static final String RESOURCE_PATH="./config/";
	
	private BufferedReader br;
	private BufferedWriter bw;
	private String lineStr;
	public  int cerNetID = -1;
	
//	private BufferedReader reader;
	
//	private  SimpleDateFormat formatInfo = new SimpleDateFormat("'['yyyy-MM-dd HH:mm:ss'][AugmentResource] '");
//	private  SimpleDateFormat formatError = new SimpleDateFormat("'['yyyy-MM-dd HH:mm:ss'][AugmentResource] '");
	
	private AugmentResource(){
		try {
			//读取配置文件信息
			init();
		} catch (IOException e) {
			log.info("Init Error, exception:"+e.getMessage());
		}
	}

    public static AugmentResource getResource(){
		return resource;
	}
	
	private void init() throws IOException{
//		ResourceBundle rb;
//		rb = new PropertyResourceBundle(new FileInputStream("prehandleconfig.properties"));
//		RESOURCE_PATH = rb.getString("resourse.path");
		if(initdistrictDB() && initispDB() && initUserInfoDB() && initAppInfoDB()&&initIpDB()){
			log.info("Augment Resources Init Success !");
		}else{
			log.info("Augment Resources Init Failed !");
		}
			
	}
	
	//IP信息数据初始化
	private boolean initIpDB() {
		try{
				File ip_long = new File(RESOURCE_PATH+"IP_long.txt");
	
				br = new BufferedReader(new InputStreamReader(new FileInputStream(ip_long),"GBK"));
				while((lineStr = br.readLine())!=null){
					ipDB.add(convertToIpInfo(lineStr));
				}
				log.info("end read ipDB info...!");
				return true;
		} catch (IOException e) {
			e.printStackTrace();
			log.info("init ipDB failed!");
			return false;
		}finally{
				try {
					if(br!=null)
						br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
	
	
	private  IpInfo convertToIpInfo(String str){
		String[] strs = str.split(" ");
		IpInfo ipInfo = new IpInfo();
		ipInfo.setLowRange(Long.parseLong(strs[0]));
		ipInfo.setDistrictID(Integer.parseInt(strs[1]));
		ipInfo.setDistrictName(ipInfo.getDistrictID() <districtDB.size() ? districtDB.get(ipInfo.getDistrictID()).getDistrictName() : districtDB.get(0).getDistrictName());
		ipInfo.setIspID(Integer.parseInt(strs[2]));
		ipInfo.setIspName(ipInfo.getIspID() < ispDB.size() ? ispDB.get(ipInfo.getIspID()).getIspName() : ispDB.get(0).getIspName());
		ipInfo.setPosition(strs[3]);
		ipInfo.setCompany(strs[4]);
		return ipInfo;
	}
	
	private boolean initdistrictDB(){
		districtDB.clear();
		//read from database if success update to /home/prehandle/districtDB.txt else read from /home/prehandle/districtDB.txt 
		Connection con=null;
		CallableStatement cs = null;
		ResultSet rs=null;
		try {
//			Class.forName(DB_DRIVER);
			con = DBResource.getInstance().getConnection();
			cs = con.prepareCall("{CALL USP_Ass_SelectRegion()}");
			rs=cs.executeQuery();
			District d;
			while(rs.next()){
				d = new District();
				d.setId(rs.getInt("RegionID"));
				d.setDistrictName(rs.getString("RegionName"));
				districtDB.add(d);
			}
		} catch (Exception e) {
			log.info("read district info from DB failed!");
		} finally{
			try {
				if(rs!=null)
					rs.close();
				if(cs!=null)
					cs.close();
				if(con!=null)
					con.close();
			} catch (SQLException e) {
				e.printStackTrace();
				log.error("initdistrictDB sql error");
			}
		}
		
		if(districtDB.size()!=0){
			File districtFile = new File(RESOURCE_PATH+"district.txt");
			try {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(districtFile),"GBK"));
				for(District dis : districtDB){
					bw.write(dis.getId()+" "+dis.getDistrictName()+"\r\n");
				}
				bw.flush();
			} catch (Exception e) {
				e.printStackTrace();
				log.error("update district info from DB to file failed!");
			} finally{
				try {
					if(br!=null)
						br.close();
					if(bw!=null)
						bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				log.info("end update district info from DB to file...");
			}
		}
		else{
			File districtFile = new File(RESOURCE_PATH+"district.txt");
			try {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(districtFile),"GBK"));
				String[] strs;
				District district;
				while((lineStr = br.readLine())!=null){
					district = new District();
					strs = lineStr.split(" ");
					district.setId(Integer.parseInt(strs[0]));
					district.setDistrictName(strs[1]);
					districtDB.add(district);
				}
			}catch (Exception e) {
				e.printStackTrace();
				log.error("read district file failed!");
			} finally{
				try {
					if(br!=null)
						br.close();
					if(bw!=null)
						bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				log.info("end read district file...");
			}
		}
		if(districtDB.size()==0){
//			log.info("init districtDB failed!");
			return false;
		}else{
//			log.info("init districtDB success!");
			return true;
		}
	}
	
	private  boolean initispDB(){
		ispDB.clear();
		
		//read from database if success update to /home/prehandle/i.txt else read from /home/prehandle/districtDB.txt 
		Connection con=null;
		CallableStatement cs = null;
		ResultSet rs=null;
		try {
//			Class.forName(DB_DRIVER);
//			con = (Connection) DriverManager.getConnection(
//					"jdbc:mysql://" + DB_LOCALADDRESS+":"+DB_LOCALPORT+"/"+DB_LOCALDATABASE, DB_LOCALUSERNAME,
//					DB_LOCALPASSWORD);
			con = DBResource.getInstance().getConnection();
			cs = con.prepareCall("{CALL USP_Ass_SelectCarrier()}");
			rs=cs.executeQuery();
			Isp i;
			while(rs.next()){
				i = new Isp();
				i.setId(rs.getInt("CarrierID"));
				i.setIspName(rs.getString("CarrierName"));
				ispDB.add(i);
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.info("read isp info from DB failed!");
		} finally{
			try {
				if(rs!=null)
					rs.close();
				if(cs!=null)
					cs.close();
				if(con!=null)
					con.close();
			} catch (SQLException e) {
				log.info("close isp info from DB fail...");
			}
		}
		if(ispDB.size()!=0){
			File ispFile = new File(RESOURCE_PATH+"isp.txt");
			try {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(ispFile),"GBK"));
				for(Isp isp : ispDB){
					bw.write(isp.getId()+" "+isp.getIspName()+"\r\n");
				}
				bw.flush();
			} catch (Exception e) {
				log.info("update isp info from DB to file failed!");
			} finally{
				try {
					if(br!=null)
						br.close();
					if(bw!=null)
						bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				log.info("end update isp info from DB to file...");
			}
		}
		else{
			File ispFile = new File(RESOURCE_PATH+"isp.txt");
			try {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(ispFile),"GBK"));
				
				lineStr = br.readLine();
				String[] strs;
				Isp isp;
				while(lineStr!=null){
					isp = new Isp();
					strs = lineStr.split(" ");
					if(strs.length<2)
						continue;
					isp.setId(Integer.parseInt(strs[0]));
					isp.setIspName(strs[1]);
					if(strs.length==3){
						strs = strs[2].split(",");
						for(String str : strs){
							isp.getKeywords().add(str);
						}
					}
					ispDB.add(isp);
					if(isp.getIspName().equals("教育网"))
						cerNetID=isp.getId();
					lineStr = br.readLine();
				}
			} catch (IOException e) {
				e.printStackTrace();
				log.info("read isp file faild!");
			} finally{
				try {
					if(br!=null)
						br.close();
					if(bw!=null)
						bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				log.info("end read isp info from txt to file...");
			}
		}
		if(ispDB.size()==0){
//			log.info("init ispDB failed!");
			return false;
		}else{
//			log.info("init ispDB success!");
			return true;
		}
	}
	
	private boolean initUserInfoDB(){
		userInfoDB.clear();
		Connection con=null;
		CallableStatement cs = null;
		ResultSet rs=null;
		try {
//			Class.forName(DB_DRIVER);
//			con = (Connection) DriverManager.getConnection(
//					"jdbc:mysql://" + DB_LOCALADDRESS+":"+DB_LOCALPORT+"/"+DB_LOCALDATABASE, DB_LOCALUSERNAME,
//					DB_LOCALPASSWORD);
			con = DBResource.getInstance().getConnection();
			cs = con.prepareCall("{CALL USP_Search_AllUser(-1,15,0,99999,?)}");
			cs.registerOutParameter(1, Types.INTEGER);
			rs=cs.executeQuery();
			UserInfo u;
			while(rs.next()){
				u = new UserInfo();
				u.ip = rs.getLong("IPLower");
				u.userGroupID = rs.getLong("UserGroupID");
				u.userID = rs.getLong("UserID");
				u.userGroupName = rs.getString("UserGroupName");
				u.userName = rs.getString("UserName");
				userInfoDB.put(u.ip, u);
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.info("init userinfoDB error!");
			return false;
		} finally{
			try {
				if(rs!=null)
					rs.close();
				if(cs!=null)
					cs.close();
				if(con!=null)
					con.close();
				log.info("end read user info...");
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return true;
	}
	
	private boolean initAppInfoDB(){
		appInfoDB.clear();
		Connection con=null;
		CallableStatement cs = null;
		ResultSet rs=null;
		try {
//			Class.forName(DB_DRIVER);
//			con = (Connection) DriverManager.getConnection(
//					"jdbc:mysql://" + DB_LOCALADDRESS+":"+DB_LOCALPORT+"/"+DB_LOCALDATABASE, DB_LOCALUSERNAME,
//					DB_LOCALPASSWORD);
			con = DBResource.getInstance().getConnection();
			cs = con.prepareCall("{CALL USP_Ass_SelectProtocol()}");
			rs=cs.executeQuery();
			AppInfo a;
			while(rs.next()){
				a = new AppInfo();
				a.appGroupID = rs.getLong("ProtocolGroupID");
				a.appID = rs.getLong("ProtocolID");
				a.appGroupName = rs.getString("ProtocolGroupName");
				a.protocolName = rs.getString("ProtocolName");
				appInfoDB.put(a.appID,a);
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.info("init appInfoDB error!");
			return false;
		} finally{
			try {
				if(rs!=null)
					rs.close();
				if(cs!=null)
					cs.close();
				if(con!=null)
					con.close();
				log.info("end read app info...");
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	public int search(long ip){
		if(ip<=0)
			return 0;
		if(ip>=ipDB.get(ipDB.size()-1).getLowRange())
			return ipDB.size()-1;
		return search(ip,0,ipDB.size()-1);
	}
	
	public int search(long ip,int min,int max){
		int mid = (max+min)/2;
		long midRange = ipDB.get(mid).getLowRange();
		if(ip==midRange)
			return mid;
		else if(ip>midRange){
			if(ip<ipDB.get(mid+1).getLowRange())
				return mid;
			else
				return search(ip,mid,max);
		}else{
			if(ip>=ipDB.get(mid-1).getLowRange())
				return mid-1;
			else
				return search(ip,min,mid);
		}
	}
	
	
	
	public List<IpInfo> getIpDB() {
		return ipDB;
	}
	public List<District> getDistrictDB() {
		return districtDB;
	}
	public List<Isp> getIspDB() {
		return ispDB;
	}
	public Map<Long, UserInfo> getUserInfoDB() {
		return userInfoDB;
	}
	public Map<Long, AppInfo> getAppInfoDB() {
		return appInfoDB;
	}


	public static void main(String[] args) {
		AugmentResource aug_resource = AugmentResource.getResource();
		System.out.println("ip info ----district name:"+aug_resource.ipDB.get(10).getDistrictName()+"isp name:"+aug_resource.ipDB.get(10).getIspName());
		System.out.println("distinct db info-----distinct name:"+aug_resource.districtDB.get(0).getDistrictName());
		System.out.println("isp db info ------isp name:"+aug_resource.ispDB.get(0).getIspName());
		UserInfo usrinfo = aug_resource.userInfoDB.values().iterator().next();
		System.out.println("userinfo db info ------user name:"+usrinfo.userName+", user group name:"+usrinfo.userGroupName);
		String distintnameutf="";
		System.out.println("utf distinct name:"+distintnameutf);
//		System.out.println("app db info ------protocal name:"+aug_resource.appInfoDB.values().iterator().next().protocolName);
		
	}
	
}
